package com.qinghong.spring_trans2.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;

/**
 * 事务只能应用到 public 方法上才会有效。
 * 事务需要从外部调用，Spring 自调事务用会失效。即相同类里边，A 方法没有事务，B 方法有事务，A 方法调用 B
 * 方法，
 * 则 B 方法的事务会失效，这点尤其要注意，因为代理模式只拦截通过代理传入的外部方法调用，所以自调用事务是不
 * 生效的。
 * 建议事务注解 @Transactional 一般添加在实现类上，而不要定义在接口上，如果加在接口类或接口方法上时，只有配置基于接口的代理这个注解才会生效。
 */
@Service
public class UserService {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    UserService2 userService2;

    // nested 子事务处理异常可以单独回滚
    // mandatory 没有事务保存 有就加入
    // supports
    // not_supported
    // nener
    // 只有runtime异常 及其子类异常 回滚
//    @Transactional(propagation = Propagation.REQUIRED)
    @Transactional(rollbackFor = IOException.class,
            noRollbackFor = ArithmeticException.class,
            readOnly = true,timeout = 3000)  // 这样io异常也回滚
    public void transfer() throws IOException {
        // 表锁 所以update的REQUIRES_NEW  还未解锁抱错  需要加索引字段  那么就变成行锁

        jdbcTemplate.update("update user set money = ? where username = ?",1,"zhangsan");
//        userService2.update();

        // 不回滚
        throw new IOException();
    }

    // 不回滚  里面是非事务方式
    @Transactional(propagation = Propagation.SUPPORTS)
//    @Transactional
    public void transfer2(){
        // 表锁 所以update的REQUIRES_NEW  还未解锁抱错  需要加索引字段  那么就变成行锁

        jdbcTemplate.update("update user set money = ? where username = ?",1,"zhangsan");
        try {
            userService2.update();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
